package com.chen.base.utils.file;

import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.chen.base.utils.CommonUtil;
import com.chen.root.base.FileChunk;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Map;

/**
 * @author: ~龙~
 * @date: 2023/6/28 9:50
 **/
@Slf4j
public class WebFileUtil {

    /** 下载文件 -> response **/
    public static void downToClient(File file){
        if (file.exists()) {
            HttpServletRequest request = CommonUtil.getRequest();
            HttpServletResponse response = CommonUtil.getResponse();
            try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
                 BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {

                setDownHeader(request, response, file.getName());
                outputStreamWrite(bos,bis);
            } catch (Exception e) {
                log.error("", e);
            }
        }
    }

    /** 下载文件 -> response **/
    public static void downToClient(FileChunk fileChunk){
        File file = new File(fileChunk.getFilePath());
        if (file.exists()) {
            HttpServletRequest request = CommonUtil.getRequest();
            HttpServletResponse response = CommonUtil.getResponse();

            byte[] bytes = new byte[fileChunk.getChunkSize()];
            try (RandomAccessFile rFile = new RandomAccessFile(fileChunk.getFilePath(), "r");
                 BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {
                setDownHeader(request, response, file.getName());

                // 定位到该分片的偏移量
                rFile.seek(fileChunk.offset());
                // 将数据读取到buffer中
                int len = rFile.read(bytes);

                bos.write(bytes, 0, len);
                bos.flush();
            } catch (Exception e) {
                log.error("", e);
            }
        }
    }

    /** 从输入流读取数据，向输出流写入数据 **/
    public static void outputStreamWrite(OutputStream os, InputStream is) throws IOException {
        int len;
        byte[] bytes = new byte[4096];
        //读取一个bytes的文件内容
        while ((len = is.read(bytes)) != -1) {
            os.write(bytes, 0, len);
        }

        os.flush();
    }

    /** 设置响应头 **/
    public static void setDownHeader(HttpServletRequest request, HttpServletResponse response, String filename) throws Exception {
        // 解决文件名乱码问题，获取浏览器类型，转换对应文件名编码格式，IE要求文件名必须是utf-8, FireFox要求是iso-8859-1编码
        String agent = request.getHeader("user-agent");
        if (agent.contains("FireFox")) {
            filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        } else {
            filename = URLEncoder.encode(filename, "UTF-8");
        }

        // 设置下载文件的mineType，告诉浏览器下载文件类型
        String mimeType = request.getServletContext().getMimeType(filename);
        response.setContentType(mimeType);
        // 设置一个响应头，无论是否被浏览器解析，都下载
        response.setHeader("Content-Disposition", "attachment; filename=" + filename);
    }

    /**
     * 以post请求下载远程文件
     * @param url 远程地址
     * @param paramMap 参数map
     * @param targetFile 目标文件
     */
    public static void postDownload(String url, Map<String, Object> paramMap, File targetFile){
        Assert.notBlank(url, "[url] is blank !");

        final HttpResponse response = createPostResponse(url, paramMap);
        if (response.isOk()) {
            response.writeBody(targetFile, null);
            return;
        }

        throw new HttpException("Server response error with status code: [{}]", response.getStatus());
    }

    /** 创建post请求的HttpResponse **/
    public static HttpResponse createPostResponse(String url, Map<String, Object> paramMap){
        return HttpUtil.createPost(url)
                .form(paramMap)
                .timeout(-1)
                .execute();
    }
}
